package com.powernode.authorization;

import cn.hutool.core.convert.Convert;
import com.powernode.constant.RedisConstant;
import com.powernode.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 鉴权管理器，判断是否拥有指定权限
 */
@Component
@Slf4j
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) {
        // TODO 扩展
        // 获取请求的uri
        String uri = context.getExchange().getRequest().getURI().getPath();
        // 从redis数据库中获取所有的权限列表
        Map<Object,Object> resourceRoleMap = redisUtil.hmget(RedisConstant.KEY_AUTH_GROUP_RESOURCE);
        // 获取资源的迭代器
        Iterator<Object> iterator = resourceRoleMap.keySet().iterator();
        // 获取请求的uri所需的权限集合
        // 创建一个路径匹配对象
        AntPathMatcher matcher = new AntPathMatcher();
        List<String> authorities = new ArrayList<>();

        while (iterator.hasNext()){
            // pattern就是访问的资源
            String pattern = (String) iterator.next();
            // 采用路径ant匹配
            if (matcher.match(pattern,uri)) {
                authorities.addAll(Convert.toList(String.class,resourceRoleMap.get(pattern)));
            }
        }
        // 遍历角色权限，添加前缀"ROLE_"
        List<String> collect = authorities.stream().map(item -> "ROLE_" + item).collect(Collectors.toList());
        // 认证通过并进行鉴权
        return authentication.filter(Authentication::isAuthenticated)
                .flatMapIterable(Authentication::getAuthorities)
                .map(GrantedAuthority::getAuthority)
                .any(role -> {
                    log.info("访问路径：{}",uri);
                    log.info("用户角色：{}",role);
                    log.info("资源所需权限：{}",collect);
                    return collect.contains(role);
                })
                .map(AuthorizationDecision::new)
                .defaultIfEmpty(new AuthorizationDecision(false));
    }
}
